import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.Vector;

import com.gargoylesoftware.htmlunit.html.DomElement;
import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlInput;
import com.gargoylesoftware.htmlunit.html.HtmlPage;


public final class Completeness {

	private static Random rnd = new Random();
	
	private Completeness() {
	}
	
	private static Object getRandomItemFromSet(Set<Object> set) {
		int randIndex = rnd.nextInt(set.size());
		return set.toArray(new Object[set.size()])[randIndex];
	}
	
	public static Set<String> getPageCompletenessSet() {
		if (SecurityFuzzer.completeness == true) {
			return SecurityFuzzer.discoverPageSet;
		}
		
		Set<String> randSet = new HashSet<String>();
		int randNumPages = rnd.nextInt(SecurityFuzzer.discoverPageSet.size());
		for (int setIndex = 0; setIndex < randNumPages; setIndex++) {
			randSet.add((String) getRandomItemFromSet(new HashSet<Object>(SecurityFuzzer.discoverPageSet)));
		}
		
		return randSet;
	}
	
	public static Set<HtmlForm> getFormCompletenessSet(HtmlPage page) {
		List<HtmlForm> pageForms = page.getForms();
		if (SecurityFuzzer.completeness == true) {
			return new HashSet<HtmlForm>(pageForms);
		}
		
		Set<HtmlForm> randSet = new HashSet<HtmlForm>();
		int randNumForms = 0;
		if (pageForms.isEmpty() == false) {
			randNumForms = 1;
			if (pageForms.size() > 1) {
				randNumForms = rnd.nextInt(pageForms.size());
			}
		}
		for (int setIndex = 0; setIndex < randNumForms; setIndex++) {
			randSet.add((HtmlForm) getRandomItemFromSet(new HashSet<Object>(pageForms)));
		}
		
		return randSet;
	}

	public static Set<HtmlInput> getInputCompletenessSet(HtmlForm form) {
		final List<HtmlInput> inputs = (List<HtmlInput>) form.getByXPath("//input");
		if (SecurityFuzzer.completeness == true) {
			return new HashSet<HtmlInput>(inputs);
		}
		
		Set<HtmlInput> randSet = new HashSet<HtmlInput>();
		int randNumInputs = 0;
		if (inputs.isEmpty() == false) {
			randNumInputs = rnd.nextInt(inputs.size());
		}
		for (int setIndex = 0; setIndex < randNumInputs; setIndex++) {
			randSet.add((HtmlInput) getRandomItemFromSet(new HashSet<Object>(inputs)));
		}
		
		return randSet;
	}
	
	public static Set<DomElement> getDomElementCompletenessSet(HtmlForm form) {
		final List<DomElement> otherElements = 
			(List<DomElement>) form.getByXPath("//input[not(@type='password') and not(@type='submit')]");
		if (SecurityFuzzer.completeness == true) {
			return new HashSet<DomElement>(otherElements);
		}
		
		Set<DomElement> randSet = new HashSet<DomElement>();
		int randNumElements = 0;
		if (otherElements.isEmpty() == false) {
			randNumElements = rnd.nextInt(otherElements.size());
		}
		for (int setIndex = 0; setIndex < randNumElements; setIndex++) {
			randSet.add((DomElement) getRandomItemFromSet(new HashSet<Object>(otherElements)));
		}
		
		return randSet;
	}
	
	public static Set<String> getFuzzVectorCompletenessSet() {
		if (SecurityFuzzer.completeness == true) {
			return Constants.fuzzVectorCollection.keySet();
		}

		Set<String> randSet = new HashSet<String>();
		int randNumFuzzVectors = rnd.nextInt(Constants.fuzzVectorCollection.size());
		for (int setIndex = 0; setIndex < randNumFuzzVectors; setIndex++) {
			randSet.add((String) getRandomItemFromSet(new HashSet<Object>(Constants.fuzzVectorCollection.keySet())));
		}
		
		return randSet;
	}
	
	public static Set<String> getAttackElementCompletenessSet(String attackVectorName) {
		Vector<String> attackVector = Constants.fuzzVectorCollection.get(attackVectorName);
		if (SecurityFuzzer.completeness == true) {
			return new HashSet<String>(attackVector);
		}

		Set<String> randSet = new HashSet<String>();
		int randNumAttackElements = rnd.nextInt(attackVector.size());
		for (int setIndex = 0; setIndex < randNumAttackElements; setIndex++) {
			randSet.add((String) getRandomItemFromSet(new HashSet<Object>(attackVector)));
		}
		
		return randSet;
	}
	
}
